#include "porting.h"

#include "sql_tree.h"
#include "lnstring.h"
#include "sql_y.h"
#include <stdio.h>


static int SQL_node_close_dummy (SQL_NODE_PTR node) { return 0; }
static int SQL_node_dump_dummy (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep) { return 0; };

int SQL_node_dump_create_table (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_update (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_select (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_name   (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_expr   (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_list   (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_spec   (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_value  (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);
int SQL_node_dump_field_def (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep);

struct SQL_node_vt_t  vt_S_NODE_NONE         = { SQL_node_close_dummy, SQL_node_dump_dummy  };
struct SQL_node_vt_t  vt_S_NODE_LIST         = { SQL_node_close_dummy, SQL_node_dump_list   };
struct SQL_node_vt_t  vt_S_NODE_SELECT       = { SQL_node_close_dummy, SQL_node_dump_select };
struct SQL_node_vt_t  vt_S_NODE_EXPR         = { SQL_node_close_dummy, SQL_node_dump_expr   };
struct SQL_node_vt_t  vt_S_NODE_NAME         = { SQL_node_close_dummy, SQL_node_dump_name   };
struct SQL_node_vt_t  vt_S_NODE_VALUE        = { SQL_node_close_dummy, SQL_node_dump_value  };

struct SQL_node_vt_t  vt_S_NODE_CREATE_USER  = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_CREATE_VIEW  = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_CREATE_TABLE = { SQL_node_close_dummy, SQL_node_dump_create_table };
struct SQL_node_vt_t  vt_S_NODE_CREATE_INDEX = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_ALTER_TABLE  = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_ALTER_INDEX  = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_ALTER_USER   = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_ALTER_CHANGE = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_DROP         = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_RENAME       = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_UPDATE       = { SQL_node_close_dummy, SQL_node_dump_update};
struct SQL_node_vt_t  vt_S_NODE_DELETE       = { SQL_node_close_dummy, SQL_node_dump_dummy };
struct SQL_node_vt_t  vt_S_NODE_SPEC         = { SQL_node_close_dummy, SQL_node_dump_spec  };
struct SQL_node_vt_t  vt_S_NODE_FIELD_DEF    = { SQL_node_close_dummy, SQL_node_dump_field_def  };

extern  SQL_NODE_VT_PTR      SQL_node_vt_list[S_NODE_TYPE_COUNT] =
{
  &vt_S_NODE_NONE             ,
  &vt_S_NODE_LIST             ,

  &vt_S_NODE_SELECT           ,
  &vt_S_NODE_EXPR             ,
  &vt_S_NODE_NAME             ,
  &vt_S_NODE_VALUE            ,

  &vt_S_NODE_CREATE_USER      ,
  &vt_S_NODE_CREATE_VIEW      ,
  &vt_S_NODE_CREATE_TABLE     ,
  &vt_S_NODE_CREATE_INDEX     ,

  &vt_S_NODE_ALTER_TABLE      ,
  &vt_S_NODE_ALTER_INDEX      ,
  &vt_S_NODE_ALTER_USER       ,
  &vt_S_NODE_ALTER_CHANGE     ,

  &vt_S_NODE_DROP             ,
  &vt_S_NODE_RENAME           ,
  &vt_S_NODE_UPDATE           ,
  &vt_S_NODE_DELETE           ,

  &vt_S_NODE_SPEC             ,
  &vt_S_NODE_FIELD_DEF        ,
};



static struct string_map_t sql_hits_map[] = 
{
  { S_HINT_ORDERED          ,"ordered"   },
  { S_HINT_JOIN_NESTED_LOOP ,"use_nl"    },
  { S_HINT_JOIN_INDEX       ,"use_idx"   },
  { S_HINT_JOIN_MERGE       ,"use_merge" },
  { S_HINT_RECOMPILE        ,"recompile" },
  { 0, NULL}
};



SQL_HINT_TYPE sql_read_hint (const char* s)
{
  return S_HINT_NONE;
}

LN_INT64 sql_read_unsigned_dec (const char* s)
{
  LN_INT64 n;

  while (*s == '0')
  {
    s++;
  };

  for ( n = 0; *s; s++)
  {
    n *= 10;
    n += (*s - '0');
  };

  return n;
}

#define PARSER_NEW_NODE() \
  (SQL_NODE_PTR) respool_alloc ( &(SQL_this_parser->mempool),sizeof(SQL_NODE));

#define PARSER_NEW_NAME_NODE() \
  (struct SQL_node_name_t *) respool_alloc ( &(SQL_this_parser->mempool),sizeof(struct SQL_node_name_t));

#define PARSER_NEW_NODE_LINK() \
  (SQL_NODE_LINK_PTR) respool_alloc ( &(SQL_this_parser->mempool),\
  sizeof(SQL_NODE_LINK));

SQL_PARSER_PTR SQL_this_parser = NULL;

int sql_parser_init(SQL_PARSER_PTR parser)
{
  LN_THREAD_PTR thrd = thrd_current();
  parser->thrd = thrd;
  parser->line = 0;
  parser->column = 0;
  parser->statements = NULL;

  respool_init( parser->mempool, parser->mempool_buffer, thrd);

  return 0;
};

void sql_parser_close (SQL_PARSER_PTR parser)
{
  respool_close (&parser->mempool);
};

SQL_NODE_PTR sql_make_expression (S_FUNC_TYPE_DEF op, SQL_NODE_PTR p1,SQL_NODE_PTR p2,SQL_NODE_PTR p3)
{
  SQL_NODE_PTR node;
  node = PARSER_NEW_NODE();

  if (node)
  {
    node->type = S_NODE_EXPR;
    node->dt.expr.op = op;
    node->dt.expr.p1 = p1;
    node->dt.expr.p2 = p2;
    node->dt.expr.p3 = p3;
    node->dt.expr.asc_flag = 0;
    node->dt.expr.as_name = NULL;
  };

  return node;
};

SQL_NODE_PTR sql_new_node (S_NODE_TYPE_DEF ty)
{
  SQL_NODE_PTR node;
  
  node = PARSER_NEW_NODE();

  memset (node, 0, sizeof(*node));

  node->type = ty;

  return node;
};

struct SQL_node_name_t * sql_new_name ()
{
  struct SQL_node_name_t * name = PARSER_NEW_NAME_NODE();
  
  name->next = NULL;
  name->flag = 0;
  name->name = NULL;
  name->prefix = NULL;

  return name;
};

SQL_NODE_PTR sql_new_list_node_and_add (SQL_NODE_PTR p)
{
  SQL_NODE_PTR node;
  SQL_NODE_LINK_PTR it;

  if (p)
  {
    node = PARSER_NEW_NODE();
    it   = PARSER_NEW_NODE_LINK();

    if (node == NULL || it == NULL)
    {
      return NULL;
    };

    it->data = p;
    it->next = NULL;

    node->type = S_NODE_LIST;
    node->dt.list.head = it;
    node->dt.list.last = it;
  }
  else
  {
    node = NULL;
  }

  return node;
};

SQL_NODE_PTR sql_add_node_to_list (SQL_NODE_PTR list, SQL_NODE_PTR p)
{
  SQL_NODE_LINK_PTR it;

  if (list && p)
  {
    if (list->type != S_NODE_LIST)
    {
      list = sql_new_list_node_and_add (list);
    }

    it = PARSER_NEW_NODE_LINK();

    it->data = p;
    it->next = NULL;

    if (list->dt.list.head)
    {
      list->dt.list.last->next = it;
      list->dt.list.last = it;
    }
    else
    {
      list->dt.list.head = it;
      list->dt.list.last = it;
    }
  }

  return list;
};


extern int yyparse();
extern int yyrestart(FILE * fp);

SQL_NODE_PTR sql_parser (SQL_PARSER_PTR parser, const char* s, int size)
{
  int rc;
  SQL_this_parser = parser;
  
  parser->buffer_size = size < 0 ? (int)strlen(s) : size;
  parser->buffer = s;
  parser->buffer_current = s;
  parser->buffer_end = s + parser->buffer_size;
  
  yyrestart(NULL);
  rc = yyparse ();

  SQL_this_parser = NULL;

  return NULL;
};

char * sql_strcat (const char* s1,const char* s2,const char* s3)
{
  const char* s[3] = { s1, s2, s3};
  char * buf, * p;
  int l[3], i, sumL;

  for (i = 0, sumL = 0; i < 3; i++)
  {
    l[i] = s[i] ? strlen(s[i]) : 0;
    sumL += l[i];
  };

  if (sumL == 0)
  {
    return NULL;
  };

  buf = respool_alloc ( &(SQL_this_parser->mempool), sumL + 1);
  
  for (p = buf, i = 0; i < 3; i++)
  {
    if (s[i])
    {
      strcpy (p, s[i]);
      p += l[i];
    }
  };

  *p = 0;

  return buf;
};

char * sql_strdup (const char* s)
{
  int size;
  char *d;

  size = s ? strlen (s) : 0;

  d = respool_alloc ( &(SQL_this_parser->mempool), size + 1);

  if (size > 0 )
  {
    memcpy (d, s, size);
  }

  d [size] = 0;

  return d;
};

int             sql_string_list_add (SQL_STRING_LIST *list, const char* s)
{
  unsigned len     = list->size;
  unsigned BufL    = ( len  + 7 ) & ~7;
  unsigned BufNewL = ( len  + 1 + 7 ) & ~7;

  if (BufL != BufNewL)
  {
    char** buf;
    
    buf = (char**) respool_alloc ( 
            &(SQL_this_parser->mempool),
            BufNewL * sizeof (void*) + sizeof(void*) );

    if (len > 0 )
    {
      memcpy ( buf, list, len * sizeof (void*) );
    }

    list->list = buf;
  };
  
  list->size = len + 1;
  list->list[len] = (char*)s;
  list->list[len + 1] = NULL;

  return 0;
};

